/*
 * VT.C
 *
 * Colorful, sorted and optionally rich directory enumeration
 * for Windows.
 *
 * This module implements routines to generate and consume VT100 style
 * escape sequences as requested.
 *
 * Copyright (c) 2015 Malcolm J. Smith
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "sdir.h"
#include "vt.h"

//
//  VT support
//

#define SdirWindowsToAnsi(COL)      \
    (((COL) & FOREGROUND_BLUE?4:0)|   \
     ((COL) & FOREGROUND_GREEN?2:0)|   \
     ((COL) & FOREGROUND_RED?1:0))

BOOL
VtSetConsoleTextAttribute(
    __in HANDLE hConsole,
    __in WORD Attribute
    )
{
    TCHAR OutputString[128];
    DWORD Length = 0;

    CHAR  AnsiForeground;
    CHAR  AnsiBackground;

    OutputString[0] = '\0';

    AnsiForeground = SdirWindowsToAnsi(Attribute&7);
    AnsiBackground = SdirWindowsToAnsi((Attribute>>4)&7);

    Length = _stprintf_s(OutputString,
                         sizeof(OutputString)/sizeof(OutputString[0]),
                         _T("%c[0;%i;%i%sm"),
                         27,
                         (Attribute & BACKGROUND_INTENSITY)?100+AnsiBackground:40+AnsiBackground,
                         30+AnsiForeground,
                         (Attribute & FOREGROUND_INTENSITY)?_T(";1"):_T("")
                         );

    //
    //  Now that we've generated the string, output it in the
    //  correct form for the device.
    //

    return SdirWriteRawStringToOutputDevice(hConsole, OutputString, Length);
}

typedef struct _VT_SUPPORT_ENTRY {
    LPTSTR   Keyword;
    DWORD    SupportFlag;
} VT_SUPPORT_ENTRY, *PVT_SUPPORT_ENTRY;

VT_SUPPORT_ENTRY VtSupportKeywords[] = {
    {_T("color"),         VT_SUPPORT_COLOR},
    {_T("extendedchars"), VT_SUPPORT_EXTDCHARS}
};

DWORD
VtQuerySupport()
{
    TCHAR SingleElement[256];
    LPTSTR Next;
    LPTSTR This;
    ULONG i;
    LPTSTR VtSupportString = NULL;
    DWORD  VtSupportLength = 0;
    DWORD  SupportedFlags = 0;

    //
    //  Load any user specified support from the environment.
    //
    //  First, count how big the allocation needs to be and allocate it.
    //

    VtSupportLength = GetEnvironmentVariable(_T("NTTERM"), NULL, 0);
    if (VtSupportLength == 0) {
        return SupportedFlags;
    }

    VtSupportString = HeapAlloc(GetProcessHeap(), 0, (VtSupportLength + 1) * sizeof(TCHAR));

    if (VtSupportString == NULL) {
        return SupportedFlags;
    }

    //
    //  Now, load any environment variables into the buffer.
    //

    GetEnvironmentVariable(_T("NTTERM"), VtSupportString, VtSupportLength);

    This = VtSupportString;

    //
    //  Now go through the list and see what support is present.
    //

    while (This != NULL) {

        //
        //  We have a mutable buffer since we just allocated it.
        //  NULL-ing as we go is really a hint to new 'secure'
        //  versions of the CRT that we don't intend to copy more
        //  TCHARs than this, so it doesn't need to gracelessly
        //  puke.
        //

        Next = _tcschr(This, ';');
        if (Next) {
            *Next = '\0';
        }

        //
        //  Ignore any leading spaces
        //

        while(*This == ' ') {
            This++;
        }

        //
        //  We want to copy as many tchars as there are between two
        //  elements, but not more than the buffer size.  Note that
        //  the printf routine below will do the right thing at end
        //  of string so it's okay to pass a larger buffer size
        //  there.
        //

        i = sizeof(SingleElement)/sizeof(SingleElement[0]);

        if (Next && ((ULONG)(Next - This) < i)) {
            i = (ULONG)(Next - This + 1);
        }

        //
        //  If this element is empty, ignore it
        //

        if (i == 0 || *This == '\0') {
            goto next_element;
        }

        _stprintf_s(SingleElement, i, _T("%s"), This);
        SingleElement[i - 1] = '\0';

        for (i = 0; i < sizeof(VtSupportKeywords)/sizeof(VtSupportKeywords[0]); i++) {
            if (_tcsicmp(SingleElement, VtSupportKeywords[i].Keyword) == 0) {

                SupportedFlags |= VtSupportKeywords[i].SupportFlag;
                break;
            }
        }

next_element:

        if (Next) {
            This = Next + 1;
        } else {
            This = NULL;
        }
    }

    HeapFree(GetProcessHeap(), 0, VtSupportString);
    return SupportedFlags;
}

// vim:sw=4:ts=4:et:
